// remotefunction.h :
//

#ifndef _REMOTE_FUNCTION_H_KOG_
#define _REMOTE_FUNCTION_H_KOG_

#include <map>
#include "basictypes.h"
#include "pipe.h"
#include "function.h"

NAMESPACE_BEGIN(kog);

class remote_function
{
	friend struct kog::tr::function_proxy;
private:
	struct function_call
	{
		int cid; // call id
		pipe::winobject wevent; // use event
		int state;
		int status;
		pipe::msgpeice_t msg;
	};

	enum rfdataflag
	{
		fcrequest = 0x01,
		fcrmtcheck = 0x02,
		fcresponse = 0x04,
	};

	struct function_return
	{
		size_t cid;
		size_t status;
	};

	enum 
	{
		MAX_SERVICE_QUEUE_SIZE = kog::pipe::MAX_QUEUE_SIZE
	};
public:
	remote_function(pipe& pipe);
	virtual ~remote_function(void);
public:
	template<typename _Fun> int entry(const std::string& name, _Fun fun)
	{
		tr::function_t<_Fun, _Fun>* tmpf = new tr::function_t<_Fun, _Fun>(fun);
		_fmap[name][typeid(_Fun).name()] = tmpf;
		return 0;
	}

	template<typename _Fun> int entry(const std::string& name, kog::tr::function_wrap_t<_Fun> fun)
	{
		typedef kog::tr::function_wrap_t<_Fun> wrap_type;
		tr::function_t<typename wrap_type::rawfun, wrap_type>* tmpf = 
			new tr::function_t<typename wrap_type::rawfun, wrap_type>(fun);
		_fmap[name][typeid(typename wrap_type::rawfun).name()] = tmpf;
		return 0;
	}
public:
	// start wait function calls and results
	void start_service();
	// stop, cleanup all data
	void stop_service();
public:
	// get a function proxy
	tr::function_proxy operator[](const std::string& name);
protected:
	// start a new call
	int _send_fcall(const char* data, int len);

	// wait send done
	int _wait_send(int cid);

	// wait remote response
	int _wait_response(int cid);

	// wait result
	template<typename _ReturnType> int _wait_result(int cid, _ReturnType& v)
	{
		char* ptr = NULL;
		int len = 0;
		int rcode = _wait_result(cid, ptr, len);
		if (rcode == 0 && len > sizeof(function_return))
		{
			unserial us(ptr + sizeof(function_return), len - sizeof(function_return));
			try {
				us.getvalue(v);
			} catch (...) {
				rcode = -1;
			}
		}
		if(ptr != NULL) 
		{
			delete []ptr;
			printf("delete data.\n");
			printf("delete recv data.\n");
		}
		return rcode;
	}
private:
	int _next_cid();
private:
	void _new_call(pipe::msgpeice_t meta);
	void _check_re(pipe::msgpeice_t meta);
	void _result_v(pipe::msgpeice_t meta);
private:
	int _wait_result(int cid, char*& v, int& len);
private:
	pipe* _pipe;
	volatile size_t _nextcid;
	pipe::winobject _cid_guard;

	std::map<std::string, std::map<std::string, tr::ifunction_t*> > _fmap;
	pipe::winobject _map_guard;

	std::map<int, function_call*> _fcalls;
	pipe::winobject _call_guard;

	volatile bool _is_servering;
	pipe::winobject _service_guard;

	pipe::winobject _sem_service_queue;
};

NAMESPACE_END(kog);

#endif